﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using Icoders.MarketTracker.Core.MasterData;
using Icoders.MarketTracker.Core.Repository.MasterDataRepositories;
using Icoders.MarketTracker.Core.Validation;
using Icoders.MarketTracker.Data.EF;
using Icoders.MarketTracker.Data.Utils;
using Icoders.MarketTracker.Data.Utils.Caching;

namespace Icoders.MarketTracker.Data.Repository.MasterDataRepositories
{
   public class UserRepository :RepositoryBase, IUserRepository
    {
       private AppDataContext _ctx;
       private ICacheProvider _cacheProvider;

       public UserRepository(AppDataContext ctx, ICacheProvider cacheProvider)
       {
           _ctx = ctx;
           _cacheProvider = cacheProvider;
       }

       public ValidationResultInfo Validate(User objToValidate)
       {
           ValidationResultInfo vri = objToValidate.BasicValidation();
           bool hasDuplicateName = GetAll().Where(v => v.Id != objToValidate.Id)
               .Any(p => p.Username == objToValidate.Username);
           if (hasDuplicateName)
               vri.Results.Add(new ValidationResult("Duplicate Username Found"));
           return vri;
       }

       public int Save(User entity)
       {
           ValidationResultInfo vri = Validate(entity);
           if (!vri.IsValid)
           {
               throw new DomainValidationException(vri, "User Details provided not valid");
           }
           DateTime date = TimeUtil.GetDateTime();
           TblUser  tbl= _ctx.TblUser.FirstOrDefault(s => s.Id == entity.Id);
           if (tbl == null)
           {
               tbl = new TblUser();
               tbl.Password = entity.Password;
               tbl.CreatedOn = date;
               tbl.StatusId = (int)MasterEntityStatus.New;
               tbl.Enabled = true;
               tbl.ChangePass = false;
               _ctx.TblUser.AddObject(tbl);
           }

           tbl.UpdatedOn = date;
           tbl.Username = entity.Username;
           tbl.LastLogin = DateTime.Now;
           tbl.LastName = entity.LastName;
           tbl.FirstName = entity.FirstName;
           tbl.Email = entity.Email;
           tbl.MobileNo = entity.PhoneNumber;
           tbl.UserTypeId = entity.UserTypeId;
           tbl.UserGroupId = entity.GroupId;
           _ctx.SaveChanges();
           _cacheProvider.Put(_cacheListKey, _ctx.TblUser.Where(x=>x.StatusId!=3).Select(s => s.Id).ToList());
           _cacheProvider.Remove(string.Format(_cacheKey, tbl.Id));
           return tbl.Id;
       }

       public User GetById(int id)
       {
           User entity = (User)_cacheProvider.Get(string.Format(_cacheKey, id));
           if (entity == null)
           {
               var tbl = _ctx.TblUser.FirstOrDefault(s => s.Id == id);
               if (tbl != null)
               {
                   entity = Map(tbl);
                   _cacheProvider.Put(string.Format(_cacheKey, entity.Id), entity);
               }

           }
           return entity;
           
       }

       private User Map(TblUser tbl)
       {
           User user= new User
           {
               Id = tbl.Id,
               UserTypeId = tbl.UserTypeId,
               Username = tbl.Username,
               UpdatedOn = tbl.UpdatedOn,
               Status = (MasterEntityStatus)tbl.StatusId,
               Password = tbl.Password,
               LastName = tbl.LastName,
               LastLogin = tbl.LastLogin != null ? tbl.LastLogin.Value : DateTime.Parse("01-jan-1900"),
               FirstName = tbl.FirstName,
               Email = tbl.Email,
               CreatedOn = tbl.CreatedOn,
               PhoneNumber = tbl.MobileNo,
               UserType = tbl.UserTypeId.ToString(),
               GroupId=tbl.UserGroupId,
               Roles=tbl.TblUserGroup.TblUserGroupRole.Where(b=>b.CanAcces).Select(s=>s.TblRole.Name).ToList(),
               Enabled=tbl.Enabled,
               ChangePass=tbl.ChangePass,
           };

           return user;
       }

       public List<User> GetAll()
       {
           //return _ctx.TblUser.ToList().Where(p => p.StatusId != (int)MasterEntityStatus.Deleted).Select(n => Map(n)).ToList();
           IList<User> entities = null;
           IList<int> ids = (IList<int>)_cacheProvider.Get(_cacheListKey);
           if (ids != null)
           {
               entities = new List<User>(ids.Count);
               foreach (int id in ids)
               {
                   User entity = GetById(id);
                   if (entity != null)
                       entities.Add(entity);
               }
           }
           else
           {
               entities = _ctx.TblUser.Where(x => x.StatusId != 3).ToList().Select(s => Map(s)).ToList();
               if (entities != null && entities.Count > 0)
               {
                   ids = entities.Select(s => s.Id).ToList(); //new List<int>(persons.Count);
                   _cacheProvider.Put(_cacheListKey, ids);
                   foreach (User p in entities)
                   {
                       _cacheProvider.Put(string.Format(_cacheKey, p.Id), p);
                   }

               }
           }
           return entities.ToList();
       }

       public void Delete(int id)
       {
           var tbl = _ctx.TblUser.FirstOrDefault(s => s.Id == id);
           if (tbl != null)
           {
               tbl.StatusId = (int)MasterEntityStatus.Deleted;
               _ctx.SaveChanges();
               _cacheProvider.Put(_cacheListKey, _ctx.TblUser.Where(x => x.StatusId != 3).Select(s => s.Id).ToList());
               _cacheProvider.Remove(string.Format(_cacheKey, tbl.Id));
           }
       }

       public bool IsLogin(string username, string password)
       {
           
           //return _ctx.TblUser.Any(a => a.Username.ToLower() == username.ToLower() && a.Password == password && a.Enabled == true);
           return GetAll().Any(a => a.Username.ToLower() == username.ToLower() && a.Password == password && a.Enabled == true);
       }

       public bool IsEnabled(string username)
       {
           //return _ctx.TblUser.Any(a => a.Username.ToLower() == username.ToLower() && a.Enabled == true);
           return GetAll().Any(a => a.Username.ToLower() == username.ToLower() && a.Enabled == true);
       }

       public bool IsChangePass(string username)
       {
           //return _ctx.TblUser.Any(a => a.Username.ToLower() == username.ToLower()  && a.ChangePass == true);
           return GetAll().Any(a => a.Username.ToLower() == username.ToLower() && a.ChangePass == true);
       }
       public bool IsLoginMobile(string username, string password)
       {

          // return _ctx.TblUser.Any(a => a.Username.ToLower() == username.ToLower() && a.Password == password && a.UserTypeId==(int)UserType.MobileAppUser);
           return
               GetAll().Any(a =>
                   a.Username.ToLower() == username.ToLower() && a.Password == password &&
                   a.UserTypeId == (int) UserType.MobileAppUser);
       }

       public void ChangePassword(string username, string oldpassword, string password)
       {
           User user = GetByUsername(username);
           if(user==null)
           {
               throw new DomainValidationException(this.BasicValidation(), "Password change failed");
           }else if(user.Password!=oldpassword)
           {
               throw new DomainValidationException(this.BasicValidation(), "Enter corrrect old Password");
           }else
           {
               var tbl = _ctx.TblUser.FirstOrDefault(p => p.Id == user.Id);
               tbl.Password = password;
               tbl.ChangePass = true;
               _ctx.SaveChanges();
               _cacheProvider.Put(_cacheListKey, _ctx.TblUser.Where(x => x.StatusId != 3).Select(s => s.Id).ToList());
               _cacheProvider.Remove(string.Format(_cacheKey, tbl.Id));
           }
       }

       public User GetByUsername(string username)
       {
           //var tbl = _ctx.TblUser.FirstOrDefault(s => s.Username.ToLower() == username.ToLower());
           //if (tbl == null) return null;
           //return Map(tbl);
           return GetAll().FirstOrDefault(s => s.Username.ToLower() == username.ToLower());
       }

       public List<User> GetByType(UserType type)
       {
           return GetAll().Where(s => s.UserTypeId == (int)UserType.MobileAppUser).ToList();
           // return _ctx.TblUser.Where(s => s.UserTypeId == (int)type && s.StatusId != (int)MasterEntityStatus.Deleted).ToList().Select(n => Map(n)).ToList();
       }

       protected override string _cacheKey
       {
           get { return "User-{0}"; }
       }

       protected override string _cacheListKey
       {
           get { return "UserList"; }
       }
    }
}
